#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <boost/filesystem.hpp>
#include "utility.hpp"
#include "Log.hpp"

using namespace std;

const string input = "./data/input";
const string output = "./data/output/output.txt";

enum exit_code
{
    SUCCESS = 0,
    ENUMERROR,
    PARSEERROR,
    WRITEERROR
};

struct Doc_Content
{
    // 文档的标题，内容，网址
    string title;
    string content;
    string url;
};

bool EnumFile(const string &src_path, vector<string> *files_list)
{
    // 初始化保存根目录信息
    boost::filesystem::path root(input);

    // 判断路径是否存在
    if (!boost::filesystem::exists(root))
    {
        lg(Fatal, "%s not exists", input.c_str());
        return false;
    }

    // 定义一个空的迭代器，用来进行判断
    boost::filesystem::recursive_directory_iterator end;
    for (boost::filesystem::recursive_directory_iterator it(root); it != end; it++)
    {
        // 只从普通文件中筛选出html文件
        if (!boost::filesystem::is_regular_file(*it) || it->path().extension() != ".html")
            continue;
        // 这个路径当前满足要求，可以放到表中
        files_list->push_back(it->path().string());
    }
    return true;
}

static bool ParseTitle(const string &file, string *title)
{
    size_t begin = file.find("<title>");
    if (begin == string::npos)
        return false;
    size_t end = file.find("</title>");
    if (end == string::npos)
        return false;
    // 将begin的信息定位到标题信息前
    begin += string("<title>").size();
    if (begin > end)
        return false;
    *title = file.substr(begin, end - begin);
    return true;
}

static bool ParseContent(const string &file, string *content)
{
    // 定义状态机的状态
    enum status
    {
        LABLE,
        CONTENT
    };

    enum status s = LABLE;
    for (char c : file)
    {
        switch (s)
        {
        case LABLE:
            if (c == '>')
                s = CONTENT;
            break;
        case CONTENT:
            if (c == '<')
                s = LABLE;
            else
            {
                // 不保留文件中的\n
                if (c == '\n')
                    c = ' ';
                content->push_back(c);
            }
            break;
        default:
            break;
        }
    }
    return true;
}

static bool ParseUrl(const string &file_path, string *url)
{
    string url_head = "https://www.boost.org/doc/libs/1_84_0/doc/html";
    // 把前面的内容去除，只保留后面的路径部分
    string url_tail = file_path.substr(input.size());
    *url = url_head + url_tail;
    return true;
}

static void showDoc(const Doc_Content &doc)
{
    cout << "title: " << doc.title << endl;
    cout << "content: " << doc.content << endl;
    cout << "url: " << doc.url << endl;
}

bool ParseHTML(const vector<string> &files_list, vector<Doc_Content> *res_list)
{
    // 遍历file_list中的每一个元素信息，提取相关内容
    for (const string &file : files_list)
    {
        // 1. 读取文件
        string res;
        if (!search_utility::FileUtility::ReadFile(file, &res))
            continue;
        // 2. 解析文件信息，存储到结构化数据中
        Doc_Content doc;
        if (!ParseTitle(res, &doc.title))
            continue;
        // 3. 解析指定的文件，提取content,就是去标签
        if (!ParseContent(res, &doc.content))
            continue;
        // 4. 解析指定的文件路径，构建url
        if (!ParseUrl(file, &doc.url))
            continue;

        res_list->push_back(move(doc));
    }
    return true;
}

bool WriteToDoc(const vector<Doc_Content> &res_list, const string &output)
{
    // 打开文件进行写入
    ofstream out(output, ios::out | ios::binary);
    if (!out.is_open())
    {
        lg(Fatal, "open %s failed!", output.c_str());
        return false;
    }
    // 打开文件后，将信息写到文件当中
    for (auto &item : res_list)
    {
        // 组件一个字符串信息
        string outstring;
        outstring += item.title;
        outstring += '\3';
        outstring += item.content;
        outstring += '\3';
        outstring += item.url;
        outstring += '\n';

        // 存储到文件中
        out.write(outstring.c_str(), outstring.size());
    }
    out.close();
    return true;
}

bool AdWrite(const vector<Doc_Content> &res_list, const string &output)
{
    // 打开文件进行写入
    ofstream out(output, ios::out | ios::binary);
    if (!out.is_open())
    {
        lg(Fatal, "open %s failed!", output.c_str());
        return false;
    }
    // 打开文件后，将信息写到文件当中
    for (auto &item : res_list)
    {
        // 组件一个字符串信息
        string outstring;
        outstring += item.title;
        outstring += '\3';
        outstring += item.content;
        outstring += '\3';
        outstring += item.url;
        outstring += '\n';

        // 存储到文件中
        out.write(outstring.c_str(), outstring.size());
    }
    out.close();
    return true;
}

bool AddAd(vector<Doc_Content>* res_list)
{
    cout << "开始读取竞价内容" << endl;
    ifstream inputFile("./data/Ad/Ad.txt");

    if (!inputFile)
    {
        cerr << "Error: Unable to open file.txt" << endl;
        return false;
    }

    // 把读取到的信息放入到结构体中
    string line;
    while (getline(inputFile, line))
    {
        int weight = 0;
        Doc_Content newinfo;
        stringstream iss(line);
        iss >> newinfo.title >> newinfo.content >> newinfo.url >> weight;
        newinfo.title += "(广告)";
        res_list->push_back(newinfo);
    }

    inputFile.close();
    cout << "读取内容完毕" << endl;

    return true;
}

int main()
{
    vector<string> files_list;
    vector<Doc_Content> res_list;

    // 0. 把竞价信息添加到res_list中
    if (!AddAd(&res_list))
    {
        lg(Fatal, "Write content to output error!");
        return WRITEERROR;
    }

    // 1. 把每个html文件名带路径保存到files_list中，方便读取其中信息
    if (!EnumFile(input, &files_list))
    {
        lg(Fatal, "enum file and name error!");
        return ENUMERROR;
    }

    // 2. 把files_list中读取到的文件内容解析到res_list中
    if (!ParseHTML(files_list, &res_list))
    {
        lg(Fatal, "parse content error!");
        return PARSEERROR;
    }

    // 3. 把res_list中解析后的内容写到output中，按照\3进行分割
    if (!WriteToDoc(res_list, output))
    {
        lg(Fatal, "Write content to output error!");
        return WRITEERROR;
    }

    return SUCCESS;
}